#pragma once
#include<iostream>
#include<memory>
using namespace std;
namespace cc
{
	template<class T>
	class auto_ptr
	{
	public:
		auto_ptr(T* ptr=nullptr)
			:_ptr(ptr)
		{}
		auto_ptr(auto_ptr<T>& aptr)
			:_ptr(aptr._ptr)
		{
			aptr._ptr = nullptr;
		}
		auto_ptr<T>& operator=(auto_ptr<T>& aptr)
		{
			delete _ptr;
			_ptr = aptr._ptr;
			aptr._ptr = nullptr;
			return *this;
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		~auto_ptr()
		{
			delete _ptr;
		}
	private:
		T* _ptr;
	};
	template<class T>
	class unique_ptr
	{
	public:
		unique_ptr(T* ptr = nullptr)
			:_ptr(ptr)
		{}
		unique_ptr(unique_ptr<T>& uptr) = delete;
		
		unique_ptr<T>& operator=(unique_ptr<T>& uptr) = delete;
		
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		~unique_ptr()
		{
			delete _ptr;
		}
	private:
		T* _ptr;
	};
	template<class T>
	class shared_ptr
	{
	public:
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			,p(new int(1))
		{}
		shared_ptr(shared_ptr<T>& sptr)
			:_ptr(sptr._ptr)
			,p(sptr.p)
		{
			(*p)++;
		}

		shared_ptr<T>& operator=(shared_ptr<T>& sptr)
		{
			if (this->_ptr != sptr._ptr && p != sptr.p)
			{
				if (--(*p) != 0)
				{
					_ptr = sptr._ptr;
					p = sptr.p;
					(*p)++;
				}
				else
				{
					cout << "delete" << endl;
					delete _ptr;
					delete p;
					_ptr = sptr._ptr;
					p = sptr.p;
					(*p)++;
				}
				return *this;
			}
			return *this;
		}

		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		int getp()
		{
			return *p;
		}
		T* get()const 
		{
			return _ptr;
		}
		~shared_ptr()
		{
			if (--(*p) == 0)
			{
				delete _ptr;
				delete p;
			}
		}
	private:
		T* _ptr;
		int* p;
	};
	template<class T>
	class weak_ptr
	{
	public:
		weak_ptr(const cc::shared_ptr<T>& sp)
			:_ptr(sp.get())
		{}
		weak_ptr<T>& operator=(const cc::shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		T* _ptr;
	};
}
